package com.leinao.filter;

import com.alibaba.fastjson.JSONObject;
import com.leinao.commons.Response;
import com.leinao.config.EnvironmentConfig;
import com.leinao.config.RedisCacheConfiguration;
import com.leinao.constant.Constant;
import com.leinao.constant.GatewayErrorEnum;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 *filterType：返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型，具体如下：
 *pre：可以在请求被路由之前调用
 *routing：在路由请求时候被调用
 *post：在routing和error过滤器之后被调用
 *error：处理请求时发生错误时被调用
 *filterOrder：通过int值来定义过滤器的执行顺序
 *shouldFilter：返回一个boolean类型来判断该过滤器是否要执行，所以通过此函数可实现过滤器的开关。在上例中，我们直接返回true，所以该过滤器总是生效。
 *run：过滤器的具体逻辑。需要注意，这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求，不对其进行路由，然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码，当然我们也可以进一步优化我们的返回，比如，通过ctx.setResponseBody(body)对返回body内容进行编辑等。
 *
 *@author wangshoufa
 *@date 2017年3月18日 下午7:56:26
 *
 */
@Component
public class AccessFilter extends ZuulFilter {
	private static Logger logger = LoggerFactory.getLogger(AccessFilter.class);
	
	@Autowired
	RedisCacheConfiguration redisCacheConfiguration;
	
	@Autowired
	EnvironmentConfig env;

	private static final String[] PASS_PATH_ARRAY = {"/login", "/openProjectInfo", "/openDataSetInfo", "/category/getCategoryCount", "/team/checkUrlData", "/team/addTeamMemberByUrl"};
	
	/*
	* 定义过滤器类型，决定该规则处理请求的哪个生命周期执行，有以下四个阶段：
	* pre: 在请求被路由之前执行
	* routing : 在路由请求调用
	* post : 在route和err之后被调用
	* error：在处理请求发生错误时调用
	*/
    @Override
    public String filterType() {
        return "pre";
    }
    
    /**
    * 过滤器执行顺序,数字越小优先级越高
    */
    @Override
    public int filterOrder() {
        return 0;
    }

	/**
	 * 是否进行过滤操作
	 */
	@Override
    public boolean shouldFilter() {
    	return true;
    }
    
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();
        response.setCharacterEncoding(Constant.DEFAULT_CHARSET);
        response.setHeader("content-type", "text/html;charset=UTF-8");//通过设置响应头控制浏览器以UTF-8的编码显示数据
        logger.info("{} request to {}", request.getMethod(), request.getRequestURL());
        for(String path : PASS_PATH_ARRAY) {
			if(StringUtils.contains(request.getRequestURL().toString(), path)) {
				logger.debug("request path: {} is pass", path);
				return null;
			}
		}

        String token = request.getHeader(Constant.USER_TOKEN);
		if(StringUtils.isBlank(token)){
			token = request.getParameter(Constant.USER_TOKEN);
		}
		String bitaToken = request.getHeader(Constant.USER_BITA_TOKEN);
		if(StringUtils.isBlank(bitaToken)){
			bitaToken = request.getParameter(Constant.USER_BITA_TOKEN);
		}
		logger.info("pai token: {}, bitaToken: {}", token, bitaToken);
		//入参为空
		if(StringUtils.isEmpty(token) || StringUtils.isEmpty(bitaToken)) {
            logger.warn("access token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(Constant.RESPONSE_STATUS_INVALID_LINK);
            ctx.setResponseBody(JSONObject.toJSONString(Response.error(Constant.RESPONSE_STATUS_SUCCESS,
					GatewayErrorEnum.HEADER_PARAM_ERROR.getSeq(), GatewayErrorEnum.HEADER_PARAM_ERROR.getDesc(),null)));
            return ctx;
        }

		Jedis jedis = null;
		try {
			JedisPool jedisPool = redisCacheConfiguration.getJedisPool();
			jedis = jedisPool.getResource();
			logger.debug("zuul gateway service get redisResource success");
			String bitaKey = env.getPrefix() + bitaToken;
			String paiKey = env.getPrefix() + token;
			String bitaValue = jedis.get(bitaKey);
			String paiValue = jedis.get(paiKey);
			if (StringUtils.isBlank(bitaValue) || StringUtils.isBlank(paiValue)) {
				logger.debug("redis token data bitaValue: {}, paiValue: {}", bitaValue, paiValue);
	            ctx.setSendZuulResponse(false);
	            ctx.setResponseStatusCode(Constant.RESPONSE_STATUS_NO_AUTHORITY);
	            ctx.setResponseBody(JSONObject.toJSONString(Response.error(Constant.RESPONSE_STATUS_SUCCESS,
						GatewayErrorEnum.LOGIN_TIMEOUT.getSeq(), GatewayErrorEnum.LOGIN_TIMEOUT.getDesc(),null)));
	            return ctx;
			}
			else {
				logger.debug("access token ok");
				return null;
			}
		} catch (Exception e) {
			logger.error("get redisResource failed");
			logger.error(e.getMessage(), e);
			ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(Constant.RESPONSE_STATUS_SERVER_ERROR);
            ctx.setResponseBody(JSONObject.toJSONString(Response.error(Constant.RESPONSE_STATUS_SUCCESS,
					GatewayErrorEnum.REDIS_RESOURCE_ERROR.getSeq(), GatewayErrorEnum.REDIS_RESOURCE_ERROR.getDesc(),null)));
            return ctx;
		} finally {
			if(jedis != null) {
				jedis.close();
			}
		}
    }
}